
#ifndef _MEM_POOL_H
#define _MEM_POOL_H

#include "Locker.h"

typedef zLock lock_t;
typedef	zFastLock mutex_t;

// Defaults for the ACE Free List
# if !defined (BE_DEFAULT_FREE_LIST_PREALLOC)
#   define BE_DEFAULT_FREE_LISTPREALLOC 0
# endif /* BE_DEFAULT_FREE_LIST_PREALLOC */

# if !defined (BE_DEFAULT_FREE_LIST_LWM)
#   define BE_DEFAULT_FREE_LIST_LWM 0
# endif /* BE_DEFAULT_FREE_LIST_LWM */

# if !defined (BE_DEFAULT_FREE_LIST_HWM)
#   define BE_DEFAULT_FREE_LIST_HWM 25000
# endif /* BE_DEFAULT_FREE_LIST_HWM */

# if !defined (BE_DEFAULT_FREE_LIST_INC)
#   define BE_DEFAULT_FREE_LIST_INC 100
# endif /* BE_DEFAULT_FREE_LIST_INC */

/**
* @class BE_Locked_Free_List
*
* @brief Implements a free list.
*
* This class maintains a free list of nodes of type T.  It
* depends on the type T having a <get_next> and <set_next>
* method.  It maintains a mutex so the freelist can be used in
* a multithreaded program .
*/
template <class T >
class BE_Locked_Free_List 
{
public:
	// = Initialization and termination.
	/**
	* Constructor takes a @a mode (i.e., BE_FREE_LIST_WITH_POOL or
	* ACE_PURE_FREE_LIST), a count of the number of nodes to
	* @a prealloc, a low and high water mark (@a lwm and @a hwm) that
	* indicate when to allocate more nodes, an increment value (@a inc)
	* that indicates how many nodes to allocate when the list must
	* grow.
	*/
	BE_Locked_Free_List (
		size_t prealloc  ,
		size_t lwm ,
		size_t hwm ,
		size_t inc );

	/// Destructor - removes all the elements from the free_list.
	virtual ~BE_Locked_Free_List (void);

	/// Inserts an element onto the free list (if it isn't past the high
	/// water mark).
	virtual void add (T *element);

	/// Takes a element off the freelist and returns it.  It creates
	/// <inc> new elements if the size is at or below the low water mark.
	virtual T *remove (void);

	/// Returns the current size of the free list.
	virtual size_t size (void);

	/// Resizes the free list to @a newsize.
	virtual void resize (size_t newsize);

protected:
	/// Allocates @a n extra nodes for the freelist.
	virtual void alloc (size_t n);

	/// Removes and frees @a n nodes from the freelist.
	virtual void dealloc (size_t n);


	/// Pointer to the first node in the freelist.
	T *free_list_;

	/// Low water mark.
	size_t lwm_;

	/// High water mark.
	size_t hwm_;

	/// Increment value.
	size_t inc_;

	/// Keeps track of the size of the list.
	size_t size_;

	/// Synchronization variable for ACE_Timer_Queue.
	mutex_t mutex_;

private:
	// = Don't allow these operations for now.
	BE_Locked_Free_List (const BE_Locked_Free_List<T> &){};
	void operator= (const BE_Locked_Free_List<T > &){};
};




// Default constructor that takes in a preallocation number
// (<prealloc>), a low and high water mark (<lwm> and <hwm>) and an
// increment value (<inc>)

template <class T>
BE_Locked_Free_List<T>::BE_Locked_Free_List (//int mode,
											 size_t prealloc,
											 size_t lwm,
											 size_t hwm,
											 size_t inc)
											 :free_list_ (0),
											 lwm_ (lwm),
											 hwm_ (hwm),
											 inc_ (inc),	
											 size_ (0)
{
	this->alloc (prealloc);
}

// Destructor - removes all the elements from the free_list

template <class T>
BE_Locked_Free_List<T>::~BE_Locked_Free_List (void)
{
	while (this->free_list_ != 0)
	{
		T *temp = this->free_list_;
		this->free_list_ = this->free_list_->get_next ();
		delete temp;
	}
}

// Inserts an element onto the free list (if we are allowed to manage
// elements withing and it pasts the high water mark, delete the
// element)

template <class T> void
BE_Locked_Free_List<T>::add (T *element)
{
	lock_t lock(mutex_);

	// Check to see that we not at the high water mark.
	if ( this->size_ < this->hwm_)
	{
		element->set_next (this->free_list_);
		this->free_list_ = element;
		this->size_++;
	}
	else
		delete element;
}

// Takes a element off the freelist and returns it.  It creates <inc>
// new elements if we are allowed to do it and the size is at the low
// water mark.

template <class T> T *
BE_Locked_Free_List<T>::remove (void)
{
	lock_t lock(mutex_);

	// If we are at the low water mark, add some nodes
	if ( this->size_ <= this->lwm_)
		this->alloc (this->inc_);

	// Remove a node
	T *temp = this->free_list_;

	if (temp != 0)
	{
		this->free_list_ = this->free_list_->get_next ();
		this->size_--;
	}

	return temp;
}


// Returns the current size of the free list

template <class T> size_t
BE_Locked_Free_List<T>::size (void)
{
	return this->size_;
}

// Resizes the free list to <newsize>

template <class T> void
BE_Locked_Free_List<T>::resize (size_t newsize)
{
	lock_t lock(mutex_);

	// Check if we are allowed to resize


	// Check to see if we grow or shrink
	if (newsize < this->size_)
	{
		this->dealloc (this->size_ - newsize);
	}
	else
	{
		this->alloc (newsize - this->size_);
	}

}

// Allocates <n> extra nodes for the freelist

template <class T> void
BE_Locked_Free_List<T>::alloc (size_t n)
{
	for (; n > 0; n--)
	{
		T *temp = 0;
		temp = new T;

		if (temp == NULL)
		{
			return ;
		}

		temp->set_next (this->free_list_);
		this->free_list_ = temp;
		this->size_++;
	}
}

// Removes and frees <n> nodes from the freelist.

template <class T> void
BE_Locked_Free_List<T>::dealloc (size_t n)
{
	for (; this->free_list_ != 0 && n > 0;
		n--)
	{
		T *temp = this->free_list_;
		this->free_list_ = this->free_list_->get_next ();
		delete temp;
		this->size_--;
	}
}


template <class T>
class CMemPoolDataNode
{
public:
	/// Return the address of free memory.
	T *addr (void)
	{
		return static_cast<T *> (static_cast <void *> (this));
	}

	/// Get the next Cached_Mem_Pool_Node in a list.
	CMemPoolDataNode<T> *get_next (void)
	{
		return this->next_;
	}

	/// Set the next Cached_Mem_Pool_Node.
	void set_next (CMemPoolDataNode<T> *ptr)
	{
		this->next_ = ptr;
	}

private:
	/**
	* Since memory is not used when placed in a free list,
	* we can use it to maintain the structure of free list.
	* I was using union to hide the fact of overlapping memory
	* usage.  However, that cause problem on MSVC.  So, I now turn
	* back to hack this with casting.
	*/
	union{
		CMemPoolDataNode<T> *next_;
		T Data;
	};
};

template <class T>
class CNewCacheAllocator
{
public:
	CNewCacheAllocator(
		size_t prealloc = BE_DEFAULT_FREE_LIST_PREALLOC,
		size_t lwm = BE_DEFAULT_FREE_LIST_LWM,
		size_t hwm = BE_DEFAULT_FREE_LIST_HWM,
		size_t inc = BE_DEFAULT_FREE_LIST_INC);
	~CNewCacheAllocator(void);
public:
	/**
	* Get a chunk of memory from free list cache.  Note that @a nbytes is
	* only checked to make sure that it's less or equal to sizeof T, and is
	* otherwise ignored since @c malloc() always returns a pointer to an
	* item of sizeof (T).
	*/
	void *malloc (size_t nbytes = sizeof (T));

	/**
	* Get a chunk of memory from free list cache, giving them
	* @a initial_value.  Note that @a nbytes is only checked to make sure
	* that it's less or equal to sizeof T, and is otherwise ignored since
	* calloc() always returns a pointer to an item of sizeof (T).
	*/
	virtual void *calloc (size_t nbytes,
		char initial_value = '\0');

	/// Return a chunk of memory back to free list cache.
	void free (void *);

private:
	/// Maintain a cached memory free list.
	BE_Locked_Free_List< CMemPoolDataNode<T> > free_list_;
};


template <class T>
CNewCacheAllocator<T>::CNewCacheAllocator(size_t prealloc,
										  size_t lwm,
										  size_t hwm,
										  size_t inc)
										  : free_list_(prealloc,lwm,hwm,inc)
{
}

template <class T>
CNewCacheAllocator<T>::~CNewCacheAllocator(void)
{
}

template <class T> void *
CNewCacheAllocator<T>::malloc (size_t nbytes)
{
	// Check if size requested fits within pre-determined size.
	if (nbytes > sizeof (T))
		return 0;

	// addr() call is really not absolutely necessary because of the way
	// ACE_Cached_Mem_Pool_Node's internal structure arranged.
	return this->free_list_.remove ()->addr ();
}

template <class T> void *
CNewCacheAllocator<T>::calloc (size_t nbytes,
							   char initial_value)
{
	// Check if size requested fits within pre-determined size.
	if (nbytes > sizeof (T))
		return 0;

	// addr() call is really not absolutely necessary because of the way
	// ACE_Cached_Mem_Pool_Node's internal structure arranged.
	void *ptr = this->free_list_.remove ()->addr ();
	if (ptr != 0)
		memset (ptr, initial_value, sizeof (T));
	return ptr;
}

template <class T> void
CNewCacheAllocator<T>::free (void * ptr)
{
	if (ptr != 0)
		this->free_list_.add ((CMemPoolDataNode<T> *) ptr) ;
}

#endif